<?php
/**
 * Created by PhpStorm.
 * Author: 芸签cms www.yunqiancms.com
 * User: sun
 * Date: 2022/8/17
 * Time: 4:19 PM
 */
namespace app\backend\modules\sys\services;

use app\common\events\plugin\PluginWasInstalled;
use app\common\exceptions\BizException;
use app\common\helpers\Cache;
use app\common\helpers\Utils;
use app\common\models\Plugin;
use app\common\services\AutoUpdate;
use app\common\services\Storage;
use ZipArchive;


class PluginMarketService
{
    public function getList($search){
        $status = intval($search['status']);
        $keyword = $search['keyword'];
        $category_name = $search['category_name'];
        $page = $search['page']?$search['page']:1;
        $limit = 30;
        $plugin_lists = $this->buildPluginList($status);
        $plugin_list = $plugin_lists['list'];
        foreach ($plugin_list as $key => $value) {
            $value['imageUrl'] = trim($value['imageUrl']);
            if (empty($value['imageUrl'])) {
                $plugin_list[$key]['imageUrl'] = '/static/images/no-img-default.png';
            }
        }
        $category_list = $plugin_lists['category_list'];
        if (!empty($keyword)) {
            foreach ($plugin_list as $k => $v) {
                if (strpos($v['title'], $keyword) === false) {
                    unset($plugin_list[$k]);
                }
            }
            $plugin_list = array_values($plugin_list);
        }
        if (!empty($category_name)) {
            foreach ($plugin_list as $k => $v) {
                if (strpos($v['category_name'], $category_name) === false) {
                    unset($plugin_list[$k]);
                }
            }
            $plugin_list = array_values($plugin_list);
        }
        $count = count($plugin_list);
        //分页
        $plugin_list = $this->page($plugin_list, $page, $limit, $count);
        $plugin_list = array_values($plugin_list);
        $free_plugin = \Setting::get('free.plugin');
        foreach ($free_plugin as $plugin) {
            foreach ($plugin_list as &$list) {
                if ($list['title'] == $plugin['title']) {
                    $list['key'] = $plugin['key'];
                    $list['secret'] = $plugin['secret'];
                }
            }
        }
        $data['data'] = $plugin_list;
        $data['category_list'] = $category_list;
        $data['current_page'] = $page;
        $data['per_page'] = $limit;
        $data['total'] = $count;
        $data['last_page'] = ceil($count / $limit);
        return $data;
    }
    /**
     * 插件处理，区分未安装，已安装，未授权
     *
     * @param int $status 0所有，1未授权，2未安装，3已安装，4可升级
     * @return array
     */
    public function buildPluginList($status = 0)
    {
        $installed_plugins_version_list = $this->loadInstalledPluginList();
        $raw_list = $this->getMarketPluginList();
        array_multisort($raw_list['list'], SORT_DESC, $raw_list['list']);
        $auth = $this->authPlugin();
        if (empty($raw_list)) {
            return [];
        }
        //所有
        $plugins_list = array();
        //未安装
        $not_installed_list = array();
        //已安装
        $installed_list = array();
        //未授权
        $preview_list = array();
        //可升级
        $up_list = array();
        //
        $un_auth_list = array();
        $plugin_name_list = array_keys($raw_list['list']);
        foreach ($plugin_name_list as $plugin_name) {
            $each_plugin = $this->buildPluginListItem($raw_list['list'][$plugin_name], $status);
            if (!$each_plugin) {
                continue;
            } else {
                $each_plugin['version_status'] = 'un_install';
                $each_plugin['empower'] = 'auth';
                $lastesVersion = $each_plugin['versionCom'][0];
                $each_plugin['latestVersion'] = '';
                foreach ($each_plugin['versionList'] as $each_version) {
                    if ($each_plugin['version'] == $each_version['version']) {
                        $each_plugin['versionDescription'] = $each_version['description'];
                        break;
                    }
                }
                $versionList = $each_plugin['versionList'];
                $versionCom = $each_plugin['versionCom'];
                unset($each_plugin['versionList']);
                unset($each_plugin['brief']);
                unset($each_plugin['versionCom']);
                //未授权
                if ($auth[$each_plugin['id']] === 0) {
                    $each_plugin['version_status'] = 'un_auth';
                    $each_plugin['empower'] = 'un_auth';
                    $un_auth_list[] = $each_plugin;
                } elseif (
                    (!empty($raw_list['list'][$plugin_name]['isPreview']) && $raw_list['list'][$plugin_name]['isPreview']) ||
                    (stripos(end($versionCom), 'rc') > 0) ||
                    (stripos(end($versionCom), 'beta') > 0) ||
                    (stripos(end($versionCom), 'alpha') > 0)) {
                    $each_plugin['version_status'] = 'preview';
                    $each_plugin['empower'] = 'auth';
                    $preview_list[] = $each_plugin;
                } elseif (!empty($installed_plugins_version_list[$each_plugin['name']])) {
                    if (version_compare($lastesVersion, $installed_plugins_version_list[$each_plugin['name']]) == 1) {
                        $each_plugin['version_status'] = 'new';
                        $each_plugin['empower'] = 'auth';
                        foreach ($versionList as $each_version) {
                            if ($lastesVersion == $each_version['version']) {
                                $each_plugin['latestVersion'] = $lastesVersion;
                                break;
                            }
                        }
                        $up_list[] = $each_plugin;
                    } else {
                        $each_plugin['version_status'] = 'installed';
                        $each_plugin['empower'] = 'auth';
                    }
                    $installed_list[] = $each_plugin;
                } else {
                    $not_installed_list[] = $each_plugin;
                }
                $plugins_list[] = $each_plugin;
            }
        }
        switch ($status) {
            case 0:
                $list['list'] = $plugins_list;
                break;
            case 1:
                $list['list'] = $un_auth_list;
                break;
            case 2:
                $list['list'] = $not_installed_list;
                break;
            case 3:
                $list['list'] = $installed_list;
                break;
            case 4:
                $list['list'] = $up_list;
                break;
        }
        $list['category_list'] = $raw_list['category_list'];
        return $list;
    }
    /**
     * 获取所有本地插件
     * @return array
     */
    public function loadInstalledPluginList()
    {
        $version_list = array();
        $resource = opendir(base_path('plugins'));
        while ($file_name = @readdir($resource)) {
            if ($file_name == '.' || $file_name == '..')
                continue;
            $plugin_path = base_path('plugins') . '/' . $file_name;
            if (is_dir($plugin_path) && file_exists($plugin_path . '/package.json')) {
                $plugin_info = json_decode(file_get_contents($plugin_path . '/package.json'), true);
                $version_list[$plugin_info['name']] = $plugin_info['version'];
            }
        }
        closedir($resource);
        return $version_list;
    }
    /**
     * 获取应用市场所有插件
     * @return mixed|null
     */
    public function getMarketPluginList() {
        $cacheKey = 'PluginMarketService:plugins-market-list';
        $res = Cache::get($cacheKey);
        if (!$res) {
            $domain = request()->getHttpHost();
            $res = (new AutoUpdate())->getAllPluginsByDomain($domain);
            Cache::put($cacheKey,$res,60 * 5);
        }
        return $res;
    }

    /**
     * 构建插件列表中plugin信息
     * @param $plugin
     * @param $status
     * @return array|bool
     */
    public function buildPluginListItem($plugin, $status)
    {
        if ($status != 2 && $plugin['switch'] == 0) {
            return false;
        }

        if (empty($plugin['name']) || empty($plugin['title']) || empty($plugin['author']) || empty($plugin['url']) || empty($plugin['version'])) {
            return false;
        } else {
            $versionList = [];
            if (!empty($plugin['old'])) {
                // $versions = array_keys($plugin['old']);
                $versionList = $plugin['old'];
            }
            $version = $plugin['version'];

            return array(
                'id' => $plugin['id'],
                'name' => $plugin['name'],

                'title' => $plugin['title'],

                'description' => empty($plugin['description']) ?'（暂无）': $plugin['description'],

                'author' => $plugin['author'],

                'version' => $version,

                'versionList' => $versionList,

                'versionCom' => $plugin['versionCom'],

                'size' => empty($plugin['size']) ? '（未知）' : $plugin['size'],

                'brief' => empty($plugin['brief']) ? '' : $plugin['brief'],
                'imageUrl' => $plugin['imageUrl'],
                'category_id' => $plugin['category_id'],
                'category_name' => $plugin['category_name'],
                'content' => is_null($plugin['content']) ? '暂无详情，请联系客服咨询' : $plugin['content'],
                'switch' => $plugin['switch']
            );
        }
    }
    //

    /**
     * 请求接口区分插件授没授权
     * @return array
     */
    public function authPlugin()
    {
        $domain = request()->getHttpHost();
        $content = (new AutoUpdate())->pluginAuthorizeByDomain($domain);
        $auth = [];
        if ($content['result'] == 1) {
            foreach ($content['data'] as $k => $v) {
                $auth[$v['plugin_id']] = $v['status'];
            }

            return $auth;
        }
        return [];
    }

    /**
     * 获取插件详情
     * @param $id
     * @param $domain
     * @return array
     */
    public function getDetail($id, $domain)
    {
        $cacheKey = 'PluginMarketService::plugin-market-detail:id:'.$id;
        $res = Cache::get($cacheKey);
        if (!$res) {
            $result = (new AutoUpdate())->getPluginDetail($id, $domain);
            $res = [];
            if ($result['result'] == '1') {
                $res = $result['data']['plugin'];
            }
            $res['imageUrl'] = trim($res['imageUrl']);
            if (empty($res['imageUrl'])) {
                $res['imageUrl'] = '/static/images/no-img-default.png';
            }
            return $res;
        }
    }

    /**
     * @param $domain
     * @param $pluginData name,version
     * @return mixed
     * @throws BizException
     */
    public function install($domain,$pluginData){
        $pluginName = $pluginData['name'];
        //if(!in_array(mb_substr($pluginName,0,4),Plugin::$localPre)){
        $res =  (new AutoUpdate())->existsPlugin($domain, $pluginData['name']);
        //\Log::debug('------插件安装升级------',json_encode($res,true));
        if (!$res) {
            throw new BizException('本地插件，无需安装。开启插件即可');
        }
        //}
        $this->downloadPlugin($pluginData);
    }

    /**
     * @param $domain
     * @param $pluginDatas
     * @return mixed
     */
    public function batchInstall($domain,$pluginDatas)
    {
        //批量安装
        $success = 0;
        $fail = 0;
        $autoUpdate = new AutoUpdate();
        foreach ($pluginDatas as $k=>$v) {
            $res =  $autoUpdate->existsPlugin($domain, $v['name']);
            try{
                $this->downloadPlugin($v);
                $success++;
            }catch (\Exception $e){
                $fail++;
            }
        }
        $res['success'] = $success;
        $res['fail'] = $fail;
        return $res;
        //return $this->successJson('安装成功:'.$success.'个，安装失败:'.$fail.'个');
    }
    /**
     * 下载安装插件
     * @param $plugin
     * @throws BizException
     */
    public function downloadPlugin($plugin)
    {
        $plugins = app('plugins');
        $name = $plugin['name'];
        $domain = request()->getHttpHost();
        if (!$name){
            throw new BizException('名字不存在！');
        }
        //Prepare download
        $tmp_dir = storage_path('plugin-download-temp');
        $tmp_path = $tmp_dir.'/tmp_'.$name.'.zip';
        if (!is_dir($tmp_dir)) {
            if (false === mkdir($tmp_dir)) {
                throw new BizException('临时文件夹创建失败');
            }
        }
        $ctx = stream_context_create([
            "ssl"=>[
                "verify_peer"=>false,
                "verify_peer_name"=>false,
            ]
        ]);

        $pluginVersionRes = [];
        $autoUpdate = new AutoUpdate();
        $pluginVersionRes = $autoUpdate->getPluginVersionByName($domain,$name);

        $code = $autoUpdate->getToken();
        $url = $pluginVersionRes['url'];
        $url = $url . "?code=" . $code . '&domain=' . $domain;
        //Connection check
        if (!$fp = @fopen($url, 'rb', false, $ctx)) {
            throw new BizException('url 打不开！');
        }
        try {
            Utils::download($url, $tmp_path);

        } catch (\Exception $e) {
            Storage::removeDir($tmp_dir);
            throw new BizException('下载失败！');
        }


        $zip = new ZipArchive();
        $res = $zip->open($tmp_path);
        if ($res === true) {
            try {
                $zip->extractTo(base_path('plugins'));
                \Log::debug($name.'解压成功 path:',base_path('plugins'));
            } catch (\Exception $e) {
                $zip->close();
                Storage::removeDir($tmp_dir);
                throw new BizException('解压失败！');
            }
        } else {
            $zip->close();
            Storage::removeDir($tmp_dir);
            throw new BizException('解压失败！');
        }
        $zip->close();

        //Clean temporary working dir
        Storage::removeDir($tmp_dir);
        Cache::flush();
        //Fire event of plugin was installed
        $plugin = $plugins->getPlugin($name);

        //执行迁移文件
        $path = 'plugins/' . $name . '/migrations';
        if (is_dir(base_path($path))) {
            \Artisan::call('migrate', ['--force' => true, '--path' => $path]);
        }

        //event(new PluginWasInstalled($plugin));
    }
    /**
     * 获取应用市场插件详细信息
     * @param $id
     * @param $domain
     * @return null|string
     */
    public function getMarketPluginDetail($id, $domain)
    {
        $json_content = (new AutoUpdate())->getPluginDetail($id,$domain);
        return $json_content;
    }
    /**
     * 分页（只在这里使用）
     * @param $list
     * @param $page
     * @param $limit
     * @param $count
     * @return array
     */
    private function page($list, $page, $limit, $count)
    {
        $start = ($page - 1) * $limit;
        $end = $page * $limit;

        if ($start > $count || $end > $count) {
            $start = floor($count / $limit) * $limit;
            $end = $count;
        }
        $new_list = [];
        for ($i = $start; $i < $end; $i++) {
            $new_list[$i] = $list[$i];
        }
        return $new_list;
    }
}